// package gress
// @Author Larry<jclarry@qq.com>
// @CreatedAt 2025/8/14 16:12
// @Desc

package gress

import (
	"fmt"
	"io"
	"net/url"
	"os"
	"path"

	"github.com/gogf/gf/v2/os/gres"
	"github.com/golang-migrate/migrate/v4/source"
)

func init() {
	source.Register("gress", &GResDriver{})
}

type GResDriver struct {
	migrations *source.Migrations
	path       string
}

func (s *GResDriver) Open(folder string) (source.Driver, error) {
	p, err := parseURI(folder)
	if err != nil {
		return nil, err
	}

	return WithInstance(p)
}

func WithInstance(p string) (source.Driver, error) {
	driver := &GResDriver{
		migrations: source.NewMigrations(),
		path:       p,
	}

	if err := driver.loadMigrations(); err != nil {
		return nil, err
	}

	return driver, nil
}

func parseURI(uri string) (string, error) {
	u, err := url.Parse(uri)
	if err != nil {
		return "", err
	}
	p := u.Opaque
	if len(p) == 0 {
		p = u.Host + u.Path
	}

	return p, nil
}

func (s *GResDriver) loadMigrations() error {

	for _, object := range gres.ScanDirFile(s.path, "*.sql") {
		_, fileName := path.Split(object.Name())
		m, err := source.DefaultParse(fileName)
		if err != nil {
			continue
		}
		if !s.migrations.Append(m) {
			return fmt.Errorf("unable to parse file %v", object.Name())
		}
	}
	return nil
}

func (s *GResDriver) Close() error {
	return nil
}

func (s *GResDriver) First() (uint, error) {
	v, ok := s.migrations.First()
	if !ok {
		return 0, os.ErrNotExist
	}
	return v, nil
}

func (s *GResDriver) Prev(version uint) (uint, error) {
	v, ok := s.migrations.Prev(version)
	if !ok {
		return 0, os.ErrNotExist
	}
	return v, nil
}

func (s *GResDriver) Next(version uint) (uint, error) {
	v, ok := s.migrations.Next(version)
	if !ok {
		return 0, os.ErrNotExist
	}
	return v, nil
}

func (s *GResDriver) ReadUp(version uint) (io.ReadCloser, string, error) {
	if m, ok := s.migrations.Up(version); ok {
		return s.open(m)
	}
	return nil, "", os.ErrNotExist
}

func (s *GResDriver) ReadDown(version uint) (io.ReadCloser, string, error) {
	if m, ok := s.migrations.Down(version); ok {
		return s.open(m)
	}
	return nil, "", os.ErrNotExist
}

func (s *GResDriver) open(m *source.Migration) (io.ReadCloser, string, error) {
	p := s.path + "/" + m.Raw
	f := gres.Get(p)
	r, err := f.Open()
	if err != nil {
		return nil, "", err
	}
	return r, m.Identifier, nil
	//key := p.Join(s.config.Prefix, m.Raw)
	//object, err := s.s3client.GetObject(&s3.GetObjectInput{
	//	Bucket: aws.String(s.config.Bucket),
	//	Key:    aws.String(key),
	//})
	//if err != nil {
	//	return nil, "", err
	//}
	//return object.Body, m.Identifier, nil
}
